using System;
using System.Data;
using System.Data.SqlClient;
using Csla;
using Csla.Data;
using Csla.Validation;

namespace PackTracker.Business
{ 
	[Serializable()] 
	public class Cliente : Csla.BusinessBase<Cliente>
	{
		#region Business Properties and Methods

		//declare members
		private int _id = 0;
		private string _nome = string.Empty;
		private string _documento = string.Empty;
		private int _telefone = 0;
		private string _email = string.Empty;
		private string _site = string.Empty;
		private int _idEndereco = 0;
		private int _idUsuario = 0;

		//declare borrowed child member(s)
		private string _idEnderecoLogradouro;
		private string _idUsuarioLogin;

		[System.ComponentModel.DataObjectField(true, true)]
		public int Id
		{
			get
			{
				CanReadProperty("Id", true);
				return _id;
			}
		}

		public string Nome
		{
			get
			{
				CanReadProperty("Nome", true);
				return _nome;
			}
			set
			{
				CanWriteProperty("Nome", true);
				if (value == null) value = string.Empty;
				if (!_nome.Equals(value))
				{
					_nome = value;
					PropertyHasChanged("Nome");
				}
			}
		}

		public string Documento
		{
			get
			{
				CanReadProperty("Documento", true);
				return _documento;
			}
			set
			{
				CanWriteProperty("Documento", true);
				if (value == null) value = string.Empty;
				if (!_documento.Equals(value))
				{
					_documento = value;
					PropertyHasChanged("Documento");
				}
			}
		}

		public int Telefone
		{
			get
			{
				CanReadProperty("Telefone", true);
				return _telefone;
			}
			set
			{
				CanWriteProperty("Telefone", true);
				if (!_telefone.Equals(value))
				{
					_telefone = value;
					PropertyHasChanged("Telefone");
				}
			}
		}

		public string Email
		{
			get
			{
				CanReadProperty("Email", true);
				return _email;
			}
			set
			{
				CanWriteProperty("Email", true);
				if (value == null) value = string.Empty;
				if (!_email.Equals(value))
				{
					_email = value;
					PropertyHasChanged("Email");
				}
			}
		}

		public string Site
		{
			get
			{
				CanReadProperty("Site", true);
				return _site;
			}
			set
			{
				CanWriteProperty("Site", true);
				if (value == null) value = string.Empty;
				if (!_site.Equals(value))
				{
					_site = value;
					PropertyHasChanged("Site");
				}
			}
		}

		public int IdEndereco
		{
			get
			{
				CanReadProperty("IdEndereco", true);
				return _idEndereco;
			}
			set
			{
				CanWriteProperty("IdEndereco", true);
				if (!_idEndereco.Equals(value))
				{
					_idEndereco = value;
					PropertyHasChanged("IdEndereco");
				}
			}
		}

		public int IdUsuario
		{
			get
			{
				CanReadProperty("IdUsuario", true);
				return _idUsuario;
			}
			set
			{
				CanWriteProperty("IdUsuario", true);
				if (!_idUsuario.Equals(value))
				{
					_idUsuario = value;
					PropertyHasChanged("IdUsuario");
				}
			}
		}

		public string idEnderecoLogradouro
		{
			get
			{
				CanReadProperty("idEnderecoLogradouro", true);
				return _idEnderecoLogradouro;
			}
		}

		public string idUsuarioLogin
		{
			get
			{
				CanReadProperty("idUsuarioLogin", true);
				return _idUsuarioLogin;
			}
		}
 
		protected override object GetIdValue()
		{
			return _id;
		}

		#endregion //Business Properties and Methods

		#region Validation Rules
		private void AddCustomRules()
		{
			//add custom/non-generated rules here...
		}

		private void AddCommonRules()
		{
			//
			// Nome
			//
			ValidationRules.AddRule(CommonRules.StringRequired, "Nome");
			ValidationRules.AddRule(CommonRules.StringMaxLength, new CommonRules.MaxLengthRuleArgs("Nome", 200));
			//
			// Documento
			//
			ValidationRules.AddRule(CommonRules.StringRequired, "Documento");
			ValidationRules.AddRule(CommonRules.StringMaxLength, new CommonRules.MaxLengthRuleArgs("Documento", 12));
			//
			// Email
			//
			ValidationRules.AddRule(CommonRules.StringMaxLength, new CommonRules.MaxLengthRuleArgs("Email", 100));
			ValidationRules.AddRule(CommonRules.RegExMatch, new CommonRules.RegExRuleArgs("Email", CommonRules.RegExPatterns.Email));
			//
			// Site
			//
			ValidationRules.AddRule(CommonRules.StringMaxLength, new CommonRules.MaxLengthRuleArgs("Site", 200));
			//
			// IdEndereco
			//
			ValidationRules.AddRule(CommonRules.IntegerMinValue, new CommonRules.IntegerMinValueRuleArgs("IdEndereco", 1));
			//
			// IdUsuario
			//
			ValidationRules.AddRule(CommonRules.IntegerMinValue, new CommonRules.IntegerMinValueRuleArgs("IdUsuario", 1));
		}

		protected override void AddBusinessRules()
		{
			AddCommonRules();
			AddCustomRules();
		}
		#endregion //Validation Rules

		#region Authorization Rules
		protected override void AddAuthorizationRules()
		{
			//TODO: Define authorization rules in Cliente
			//AuthorizationRules.AllowRead("Id", "ClienteReadGroup");
			//AuthorizationRules.AllowRead("Nome", "ClienteReadGroup");
			//AuthorizationRules.AllowRead("Documento", "ClienteReadGroup");
			//AuthorizationRules.AllowRead("Telefone", "ClienteReadGroup");
			//AuthorizationRules.AllowRead("Email", "ClienteReadGroup");
			//AuthorizationRules.AllowRead("Site", "ClienteReadGroup");
			//AuthorizationRules.AllowRead("IdEndereco", "ClienteReadGroup");
			//AuthorizationRules.AllowRead("IdUsuario", "ClienteReadGroup");

			//AuthorizationRules.AllowWrite("Nome", "ClienteWriteGroup");
			//AuthorizationRules.AllowWrite("Documento", "ClienteWriteGroup");
			//AuthorizationRules.AllowWrite("Telefone", "ClienteWriteGroup");
			//AuthorizationRules.AllowWrite("Email", "ClienteWriteGroup");
			//AuthorizationRules.AllowWrite("Site", "ClienteWriteGroup");
			//AuthorizationRules.AllowWrite("IdEndereco", "ClienteWriteGroup");
			//AuthorizationRules.AllowWrite("IdUsuario", "ClienteWriteGroup");
		}


		public static bool CanGetObject()
		{
			//TODO: Define CanGetObject permission in Cliente
			return true;
			//if (Csla.ApplicationContext.User.IsInRole("ClienteViewGroup"))
			//	return true;
			//return false;
		}

		public static bool CanAddObject()
		{
			//TODO: Define CanAddObject permission in Cliente
			return true;
			//if (Csla.ApplicationContext.User.IsInRole("ClienteAddGroup"))
			//	return true;
			//return false;
		}

		public static bool CanEditObject()
		{
			//TODO: Define CanEditObject permission in Cliente
			return true;
			//if (Csla.ApplicationContext.User.IsInRole("ClienteEditGroup"))
			//	return true;
			//return false;
		}

		public static bool CanDeleteObject()
		{
			//TODO: Define CanDeleteObject permission in Cliente
			return true;
			//if (Csla.ApplicationContext.User.IsInRole("ClienteDeleteGroup"))
			//	return true;
			//return false;
		}
		#endregion //Authorization Rules

		#region Factory Methods
		private Cliente()
		{ /* require use of factory method */ }

		public static Cliente NewCliente()
		{
			if (!CanAddObject())
				throw new System.Security.SecurityException("User not authorized to add a Cliente");
			return DataPortal.Create<Cliente>();
		}

		public static Cliente GetCliente(int id)
		{
			if (!CanGetObject())
				throw new System.Security.SecurityException("User not authorized to view a Cliente");
			return DataPortal.Fetch<Cliente>(new Criteria(id));
		}

		public static void DeleteCliente(int id)
		{
			if (!CanDeleteObject())
				throw new System.Security.SecurityException("User not authorized to remove a Cliente");
			DataPortal.Delete(new Criteria(id));
		}

		public override Cliente Save()
		{
			if (IsDeleted && !CanDeleteObject())
				throw new System.Security.SecurityException("User not authorized to remove a Cliente");
			else if (IsNew && !CanAddObject())
				throw new System.Security.SecurityException("User not authorized to add a Cliente");
			else if (!CanEditObject())
				throw new System.Security.SecurityException("User not authorized to update a Cliente");

			return base.Save();
		}

		#endregion //Factory Methods

		#region Child Factory Methods
		internal static Cliente NewClienteChild()
		{
			Cliente child = new Cliente();
			child.ValidationRules.CheckRules();
			child.MarkAsChild();
			return child;
		}

		internal static Cliente GetCliente(SafeDataReader dr)
		{
			Cliente child =  new Cliente();
			child.MarkAsChild();
			child.Fetch(dr);
			return child;
		}
		#endregion //Child Factory Methods

		#region Data Access

		#region Criteria

		[Serializable()]
		private class Criteria
		{
			public int Id;

			public Criteria(int id)
			{
				this.Id = id;
			}
		}

		#endregion //Criteria

		#region Data Access - Create
		[RunLocal]
		protected override void DataPortal_Create()
		{
			ValidationRules.CheckRules();
		}

		#endregion //Data Access - Create

		#region Data Access - Fetch
		private void DataPortal_Fetch(Criteria criteria)
		{
			using (SqlConnection cn = new SqlConnection(Database.DefaultConnection))
			{
				cn.Open();

				ExecuteFetch(cn, criteria);
			}//using
		}

		private void ExecuteFetch(SqlConnection cn, Criteria criteria)
		{
			using (SqlCommand cm = cn.CreateCommand())
			{
				cm.CommandType = CommandType.StoredProcedure;
				cm.CommandText = "pr_GetCliente";
				cm.Parameters.AddWithValue("@id", criteria.Id);

				using (SafeDataReader dr = new SafeDataReader(cm.ExecuteReader()))
				{
					dr.Read();
					FetchObject(dr);
					ValidationRules.CheckRules();

					//load child object(s)
					FetchChildren(dr);
				}
			}//using
		}

		#endregion //Data Access - Fetch

		#region Data Access - Insert
		protected override void DataPortal_Insert()
		{
			using (SqlConnection cn = new SqlConnection(Database.DefaultConnection))
			{
				cn.Open();

				ExecuteInsert(cn);

				//update child object(s)
				UpdateChildren(cn);
			}//using

		}

		#endregion //Data Access - Insert

		#region Data Access - Update
		protected override void DataPortal_Update()
		{
			using (SqlConnection cn = new SqlConnection(Database.DefaultConnection))
			{
				cn.Open();

				if (base.IsDirty)
				{
					ExecuteUpdate(cn);
				}

				//update child object(s)
				UpdateChildren(cn);
			}//using

		}

		#endregion //Data Access - Update

		#region Data Access - Delete
		protected override void DataPortal_DeleteSelf()
		{
			DataPortal_Delete(new Criteria(_id));
		}

		private void DataPortal_Delete(Criteria criteria)
		{
			using (SqlConnection cn = new SqlConnection(Database.DefaultConnection))
			{
				cn.Open();

				ExecuteDelete(cn, criteria);

			}//using

		}

		private void ExecuteDelete(SqlConnection cn, Criteria criteria)
		{
			using (SqlCommand cm = cn.CreateCommand())
			{
				cm.CommandType = CommandType.StoredProcedure;
				cm.CommandText = "pr_DeleteCliente";

				cm.Parameters.AddWithValue("@id", criteria.Id);

				cm.ExecuteNonQuery();
			}//using
		}
		#endregion //Data Access - Delete

		#region Data Access - Fetch
		private void Fetch(SafeDataReader dr)
		{
			FetchObject(dr);
			MarkOld();
			ValidationRules.CheckRules();

			//load child object(s)
			if(!this.IsChild)
				FetchChildren(dr);
		}

		private void FetchObject(SafeDataReader dr)
		{
			_id = dr.GetInt32("id");
			_nome = dr.GetString("Nome");
			_documento = dr.GetString("Documento");
			_telefone = dr.GetInt32("Telefone");
			_email = dr.GetString("Email");
			_site = dr.GetString("Site");
			_idEndereco = dr.GetInt32("idEndereco");
			_idUsuario = dr.GetInt32("idUsuario");
			_idEnderecoLogradouro = dr.GetString("idEnderecoLogradouro");
			_idUsuarioLogin = dr.GetString("idUsuarioLogin");
		}

		private void FetchChildren(SafeDataReader dr)
		{
		}
		#endregion //Data Access - Fetch

		#region Data Access - Insert
		internal void Insert(SqlConnection cn)
		{
			if (!IsDirty) return;

			ExecuteInsert(cn);
			MarkOld();

			//update child object(s)
			UpdateChildren(cn);
		}

		private void ExecuteInsert(SqlConnection cn)
		{
			using (SqlCommand cm = cn.CreateCommand())
			{
				cm.CommandType = CommandType.StoredProcedure;
				cm.CommandText = "pr_AddCliente";

				AddInsertParameters(cm);

				cm.ExecuteNonQuery();

				_id = (int)cm.Parameters["@id"].Value;
			}//using
		}

		private void AddInsertParameters(SqlCommand cm)
		{
			cm.Parameters.AddWithValue("@Nome", _nome);
			cm.Parameters.AddWithValue("@Documento", _documento);
			cm.Parameters.AddWithValue("@Telefone", _telefone);
			if (_email.Length > 0)
				cm.Parameters.AddWithValue("@Email", _email);
			else
				cm.Parameters.AddWithValue("@Email", DBNull.Value);
			if (_site.Length > 0)
				cm.Parameters.AddWithValue("@Site", _site);
			else
				cm.Parameters.AddWithValue("@Site", DBNull.Value);
			cm.Parameters.AddWithValue("@idEndereco", _idEndereco);
			cm.Parameters.AddWithValue("@idUsuario", _idUsuario);
			cm.Parameters.AddWithValue("@id", _id);
			cm.Parameters["@id"].Direction = ParameterDirection.Output;
		}
		#endregion //Data Access - Insert

		#region Data Access - Update
		internal void Update(SqlConnection cn)
		{
			if (!IsDirty) return;

			if (base.IsDirty)
			{
				ExecuteUpdate(cn);
				MarkOld();
			}

			//update child object(s)
			UpdateChildren(cn);
		}

		private void ExecuteUpdate(SqlConnection cn)
		{
			using (SqlCommand cm = cn.CreateCommand())
			{
				cm.CommandType = CommandType.StoredProcedure;
				cm.CommandText = "pr_UpdateCliente";

				AddUpdateParameters(cm);

				cm.ExecuteNonQuery();

			}//using
		}

		private void AddUpdateParameters(SqlCommand cm)
		{
			cm.Parameters.AddWithValue("@id", _id);
			cm.Parameters.AddWithValue("@Nome", _nome);
			cm.Parameters.AddWithValue("@Documento", _documento);
			cm.Parameters.AddWithValue("@Telefone", _telefone);
			if (_email.Length > 0)
				cm.Parameters.AddWithValue("@Email", _email);
			else
				cm.Parameters.AddWithValue("@Email", DBNull.Value);
			if (_site.Length > 0)
				cm.Parameters.AddWithValue("@Site", _site);
			else
				cm.Parameters.AddWithValue("@Site", DBNull.Value);
			cm.Parameters.AddWithValue("@idEndereco", _idEndereco);
			cm.Parameters.AddWithValue("@idUsuario", _idUsuario);
		}

		private void UpdateChildren(SqlConnection cn)
		{
		}
		#endregion //Data Access - Update

		#region Data Access - Delete
		internal void DeleteSelf(SqlConnection cn)
		{
			if (!IsDirty) return;
			if (IsNew) return;

			ExecuteDelete(cn, new Criteria(_id));
			MarkNew();
		}
		#endregion //Data Access - Delete
		#endregion //Data Access
	}
}
